package com.example.nionetty.server;

import javax.print.DocFlavor;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

/**
 * @Author: ZhaoJie
 * @Date: 2022/3/24
 * @Description :
 * @Modify :
 * ===================================================
 * Modifier        Modifytime        Description
 * ===================================================
 */
public class ServerOnlineChatRoom {
    /**
     * 定义selector
     */
    private Selector selector;
    private ServerSocketChannel listenChannel;
    private static final int PORT = 6667;

    /**
     * @author: zhaojie
     * @date: 2022/3/24
     * @method: ServerOnlineChatRoom: 初始化服务类
     * @param:
     * @class:  ServerOnlineChatRoom
     * @return:
     */
    public ServerOnlineChatRoom() {
        try {
            //得到选择器
            selector = Selector.open();
            //ServerSocketChannel
            listenChannel = ServerSocketChannel.open();
            //绑定端口
            listenChannel.socket().bind(new InetSocketAddress(PORT));
            //设置非阻塞模式
            listenChannel.configureBlocking(false);
            //将该 listenChannel 注册到 selector
            listenChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * @author: zhaojie
     * @date: 2022/3/24
     * @method: listen: 监听方法
     * @param: 
     * @class:  ServerOnlineChatRoom
     * @return: 
     */
    public void listen() {
        try {
            // 循环处理，处理selector中的事件
            while (true) {
                int count = selector.select();
                if (count > 0) {
                    //遍历得到selectionkey 集合
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()) {
                        // 获取发生事件的key
                        SelectionKey key = iterator.next();

                        //对不同的事件进行处理
                        //监听到accept，即客户端有请求发送过来
                        if (key.isAcceptable()) {
                            SocketChannel socketChannel = listenChannel.accept();
                            //设置为非阻塞
                            socketChannel.configureBlocking(false);
                            socketChannel.register(selector, SelectionKey.OP_READ);
                            //服务端显示上线信息
                            System.out.println(socketChannel.getRemoteAddress() + " 上线 ");
                        }
                        // 监听到通道中有readable事件，意思是客户端将数据写入通道中，服务端从中读数据
                        if (key.isReadable()) {
                            // 从socketChannel中读取数据
                            readChannelData(key);
                        }

                        //删除执行完毕的key
                        iterator.remove();
                    }
                } else {
                    System.out.println("等待。。。。");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 发生异常执行
        }
    }

    /**
     * @author: zhaojie
     * @date: 2022/3/24
     * @method: readChannelData: 获取客户端发送过来的消息
     * @param:
     * @class:  ServerOnlineChatRoom
     * @return:
     */
    public void readChannelData(SelectionKey key) {
        SocketChannel channel = null;
        try {
            //得到channel
            channel = (SocketChannel) key.channel();
            //创建buffer
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int count = channel.read(buffer);
            if (count > 0) {
                //将缓存区的数据转成字符串
                String msg = new String(buffer.array());
                System.out.println("from客户端：" + msg.substring(0, count));
                //想起他客户端发送消息，除了自己
                sendMessageToOtherUser(msg, channel);
            }
        } catch (IOException e) {
            try {
                System.out.println(channel.getRemoteAddress() + "离线了..");
                //取消注册
                key.cancel();
                //关闭通道
                channel.close();
            } catch (IOException e2) {
                e2.printStackTrace();
            }
        }

    }

    /**
     * @author: zhaojie
     * @date: 2022/3/24
     * @description:
     * @method: sendMessageToOtherUser: 向注册的其他客户端发送消息
     * @param:
     * @class:  ServerOnlineChatRoom
     * @return:
     */
    public void sendMessageToOtherUser(String msg, SocketChannel selfChannel) throws IOException {
        System.out.println("消息转发中。。。。");
        //遍历素有注册到selector的客户端，并且排除自己
        for (SelectionKey key : selector.keys()) {
            //通过key拿到对应的channel
            Channel targetChannel = key.channel();
            //排除自己
            if (targetChannel instanceof SocketChannel && targetChannel != selfChannel) {
                //将channel转型
                SocketChannel toChannel = (SocketChannel) targetChannel;
                //将字符串变为字节
                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
                //将数据放入channel
                toChannel.write(buffer);

            }
        }
    }

    /**
     * @author: zhaojie
     * @date: 2022/3/24
     * @description:
     * @method: main: 初始化类
     * @param:
     * @class:  ServerOnlineChatRoom
     * @return:
     */
    public static void main(String[] args) {
        //创建服务器对象
        ServerOnlineChatRoom groupChatServer = new ServerOnlineChatRoom();
        groupChatServer.listen();
    }

}
